﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class UnicodeEx
{
    /// <summary>
    /// 自定义字体字符
    /// </summary>
    public HashSet<long> CustomFont;
    public struct CodeInfo
    {
        public int start;
        public ulong fullCode;
        public int fbit;
        public int halfCode;
        public int hbit;
        /// <summary>
        /// 不包含修饰符，连接符
        /// </summary>
        public int charCount;
    }
    /// <summary>
    /// 获取Unicode字符文本长度
    /// </summary>
    /// <param name="str"></param>
    /// <param name="start"></param>
    /// <returns></returns>
    public static int GetNextTextLength(string str, int start)
    {
        int count = 0;
        int os = start;
        int len = str.Length;
        for (int i = 0; i < 4; i++)
        {
            Char c = str[os];
            int cc = 0;
            if ((c & 0b1000_0000_0000_0000) > 0)//Unicode
            {
                cc++;
                if ((c & 0b100_0000_0000_0000) > 0)
                {
                    cc++;
                    if ((c & 0b10_0000_0000_0000) > 0)
                    {
                        cc++;
                        if ((c & 0b1_0000_0000_0000) > 0)
                        {
                            cc++;
                        }
                    }
                }
            }
            else// ASCII
            {
                cc = 1;
            }
            count += cc;
            os += cc;
            if (os >= len)
                break;
            char next = str[os];
            if (next == 55356)//表情修饰符
            {
                count += 2;
                os += 2;
                if (os >= len)
                    break;
                next = str[os];
            }
            if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
            {
                count++;
                os++;
                if (os >= len)
                    break;
                next = str[os];
                if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
                {
                    count++;
                    os++;
                }
            }
            else break;
        }
        return count;
    }
    public static int CheckLength2(string str, int start)
    {
        int count = 0;
        int os = start;
        int len = str.Length;
        long code = 0;
        int bit = 0;
        //bool link = false;
        for (int i = 0; i < 4; i++)
        {
            Char c = str[os];
            int cc = 0;
            if ((c & 0b1000_0000_0000_0000) > 0)//Unicode
            {
                cc++;
                code |= (long)(c & 0b11_1111);
                code <<= 6;
                code |= (long)((c >> 8) & 0b111);
                if ((c & 0b100_0000_0000_0000) > 0)
                {
                    Char n = str[os + 1];
                    code <<= 3;
                    code |= (long)(n & 0b11_1111);
                    code <<= 6;
                    code |= (long)((n >> 8) & 0b11_1111);
                    cc++;
                    if ((c & 0b10_0000_0000_0000) > 0)
                    {
                        n = str[os + 2];
                        code <<= 6;
                        code |= (long)(n & 0b11_1111);
                        code <<= 6;
                        code |= (long)((n >> 8) & 0b11_1111);
                        cc++;
                        if ((c & 0b1_0000_0000_0000) > 0)
                        {
                            n = str[os + 3];
                            code <<= 6;
                            code |= (long)(n & 0b11_1111);
                            code <<= 6;
                            code |= (long)((n >> 8) & 0b11_1111);
                            cc++;
                        }
                    }
                }
                bit += cc * 12 - 3;
            }
            else
            {
                if (c < 128)//ASCII
                {
                    code <<= 7;
                    code |= (long)(c & 0b111_1111);
                    bit += 7;
                }
                else
                {
                    code <<= 14;
                    code |= (long)(c & 0b11_1111_1111_1111);
                    bit += 14;
                }
                cc = 1;
            }
            count += cc;
            os += cc;
            if (os >= len)
                break;
            char next = str[os];
            if (next == 55356)//表情修饰符
            {
                count += 2;
                os += 2;
                if (os >= len)
                    break;
                next = str[os];
            }
            if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
            {
                count++;
                os++;
                if (os >= len)
                    break;
                next = str[os];
                if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
                {
                    count++;
                    os++;
                }
            }
            else break;
        }
        //Console.WriteLine(bit);
        return bit;
    }
    static CodeInfo[] codeInfos = new CodeInfo[8];
    public static CodeInfo[] combineInfos = new CodeInfo[8];
    static void GetCodePoint(string str, int start, ref CodeInfo info)
    {
        int os = start;
        int cc = 0;
        ulong fullCode = 0;
        UInt16 c = str[os];
        if (c == 0xDB40)//表情修饰符
        {
            info.charCount = 2;
            info.fullCode = str[os + 1];
            info.fbit = 16;
            return;
        }
        if ((c & 0b1000_0000_0000_0000) > 0)//Unicode
        {
            fullCode |= c;
            cc++;
            if ((c & 0b100_0000_0000_0000) > 0)
            {
                UInt16 n = str[os + 1];
                fullCode <<= 16;
                fullCode |= n;
                cc++;
                if ((c & 0b10_0000_0000_0000) > 0)
                {
                    n = str[os + 2];
                    fullCode <<= 16;
                    fullCode |= n;
                    cc++;
                    if ((c & 0b1_0000_0000_0000) > 0)
                    {
                        n = str[os + 3];
                        fullCode <<= 16;
                        fullCode |= n;
                        cc++;
                    }
                }
            }
            info.fbit = cc * 16;//=48-3
            info.fullCode = fullCode;
            info.charCount = cc;
        }
        else
        {
            if (c < 128)//ASCII
            {
                info.fullCode = c ;
                info.fbit = 8;
            }
            else
            {
                info.fullCode = c ;
                info.fbit = 16;
            }
            info.charCount = 1;
        }
    }
    public static uint GetUnicode(string str, int start)
    {
        int os = start;
        int len = str.Length;

        int pc = 0;
        for (int i = 0; i < 8; i++)
        {
            if (os >= len)
                break;
            codeInfos[i].start = os;
            GetCodePoint(str, os, ref codeInfos[pc]);
            int cc = codeInfos[pc].charCount;
            os += cc;
            pc++;
            if (os >= len)
                break;
            if (cc == 2)
            {
                if (str[os] == str[os - 2])//宽字符
                {
                    GetCodePoint(str, os, ref codeInfos[pc]);
                    os += codeInfos[pc].charCount;
                    pc++;
                }
            }
            if (os >= len)
                break;
            UInt16 next = str[os];
            if (next == 0xDB40)//表情修饰符
            {
                continue;
            }
            if (next == 65038 || next == 65039)//变体选择符
            {
                os++;
                if (os >= len)
                    break;
                next = str[os];
            }
            if (next == 8205 || next == 8204)//表情连接符+变体选择符
            {
                os++;
                if (os >= len)
                    break;
            }
            else break;
        }
        if (pc > 1)
        {
            Bit128 bit128 = new Bit128();
            int offset = 0;
            for (int i = 0; i < pc; i++)
            {
                bit128.Write(codeInfos[i].fullCode, offset, codeInfos[i].fbit);
                offset += codeInfos[i].fbit;
            }
            if (offset > 32)
                return bit128.GetMD4();
            return (UInt32)bit128.a;
         
        }
        else
        {
            return (uint)codeInfos[0].fullCode;
        }
    }
    static void CombineBit(long a, int ac, long b, int bc)
    {
        if (ac + bc > 64)
        {
            int r = 64 - ac;
            a <<= bc;
            a |= b >> (bc - r);
        }
        else
        {
            a <<= bc;
            a |= b;
        }
    }
    
    /// <summary>
    /// 根据注册的字体字符进行匹配
    /// </summary>
    /// <param name="str"></param>
    /// <param name="start"></param>
    /// <param name="codeCount"></param>
    /// <returns></returns>
    public int MatchFont(string str, int start, ref int codeCount)
    {
        int count = 0;
        int os = start;
        int len = str.Length;

        int pc = 0;
        for (int i = 0; i < 4; i++)
        {
            codeInfos[i].start = os;
            //GetCodePoint(str, os, ref codeInfos[pc]);
            count += codeInfos[pc].charCount;
            os += codeInfos[pc].charCount;
            pc++;

            if (os >= len)
                break;
            char next = str[os];
            if (next == 55356)//表情修饰符
            {
                count += 2;
                os += 2;
                if (os >= len)
                    break;
                next = str[os];
            }
            if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
            {
                count++;
                os++;
                if (os >= len)
                    break;
                next = str[os];
                if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
                {
                    count++;
                    os++;
                }
            }
            else break;
        }
        if (pc > 1)
        {
            int s = 0;
            int fc = 0;
            for (; fc < pc; fc++)
            {
                combineInfos[fc].start = codeInfos[s].start;
                s += MatchFont(s, pc, ref combineInfos[fc].fullCode);
                if (s >= pc)
                    break;
            }
            codeCount = fc;
        }
        else
        {
            codeCount = 1;
        }
        return count;
    }
    int MatchFont(int s, int end, ref ulong combine)
    {
        //ulong fullCode = codeInfos[s].fullCode;
        //for (int i = s + 1; i < end; i++)
        //{
        //    fullCode <<= codeInfos[i].hbit;
        //    fullCode |= (ulong)codeInfos[i].halfCode;
        //}
        //for (int i = end - 1; i > s; i--)
        //{
        //    if (CustomFont.Contains(fullCode))//进行字体匹配
        //    {
        //        combine = fullCode;

        //        return i - s;
        //    }
        //    fullCode >>= codeInfos[i].hbit;
        //}
        //combine = codeInfos[s].fullCode;
        return 1;
    }
   //static void GetCodePoint(string str, int start, ref CodeInfo info)
   // {
   //     int os = start;
   //     int cc = 0;
   //     long fullCode = 0;
   //     int halfCode = 0;
   //     UInt16 c = str[os];
   //     if ((c & 0b1000_0000_0000_0000) > 0)//Unicode
   //     {
   //         cc++;
   //         fullCode |= (long)(c & 0b11_1111);
   //         fullCode <<= 6;
   //         halfCode |= (c & 0b111);
   //         halfCode <<= 3;
   //         int n = c >> 8;
   //         fullCode |= (long)(n & 0b111);
   //         halfCode |= n & 0b11;
   //         if ((c & 0b100_0000_0000_0000) > 0)
   //         {
   //             n = str[os + 1];
   //             fullCode <<= 3;
   //             halfCode <<= 2;
   //             fullCode |= (long)(n & 0b11_1111);
   //             fullCode <<= 6;
   //             halfCode |= (n & 0b111);
   //             halfCode <<= 3;
   //             n >>= 8;
   //             fullCode |= (long)(n & 0b11_1111);
   //             halfCode |= n & 0b111;
   //             cc++;
   //             if ((c & 0b10_0000_0000_0000) > 0)
   //             {
   //                 n = str[os + 2];
   //                 fullCode <<= 6;
   //                 halfCode <<= 3;
   //                 fullCode |= (long)(n & 0b11_1111);
   //                 fullCode <<= 6;
   //                 halfCode |= (n & 0b111);
   //                 halfCode <<= 3;
   //                 n >>= 8;
   //                 fullCode |= (long)(n & 0b11_1111);
   //                 halfCode |= n & 0b111;
   //                 cc++;
   //                 if ((c & 0b1_0000_0000_0000) > 0)
   //                 {
   //                     n = str[os + 3];
   //                     fullCode <<= 6;
   //                     halfCode <<= 3;
   //                     fullCode |= (long)(n & 0b11_1111);
   //                     fullCode <<= 6;
   //                     halfCode |= (n & 0b111);
   //                     halfCode <<= 3;
   //                     n >>= 8;
   //                     fullCode |= (long)(n & 0b11_1111);
   //                     halfCode |= n & 0b111;
   //                     cc++;
   //                 }
   //             }
   //         }
   //         info.fbit = cc * 12 - 3;//=48-3
   //         info.hbit = cc * 6 - 1;//=24-1
   //         info.fullCode = fullCode;
   //         info.halfCode = halfCode;
   //         info.charCount = cc;
   //     }
   //     else
   //     {
   //         if (c < 128)//ASCII
   //         {
   //             info.fullCode = info.halfCode = c & 0b111_1111;
   //             info.fbit = info.hbit = 7;
   //         }
   //         else
   //         {
   //             info.fullCode = info.halfCode = c & 0b11_1111_1111_1111;
   //             info.fbit = info.hbit = 14;
   //         }
   //         info.charCount = 1;
   //     }
   // }
    //public long GetCodePoint(string str, int start)
    //{
    //    int os = start;
    //    int len = str.Length;

    //    int pc = 0;
    //    for (int i = 0; i < 4; i++)
    //    {
    //        codeInfos[i].start = os;
    //        GetCodePoint(str, os, ref codeInfos[pc]);
    //        os += codeInfos[pc].charCount;
    //        pc++;

    //        if (os >= len)
    //            break;
    //        char next = str[os];
    //        if (next == 55356)//表情修饰符
    //        {
    //            os += 2;
    //            if (os >= len)
    //                break;
    //            next = str[os];
    //        }
    //        if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
    //        {
    //            os++;
    //            if (os >= len)
    //                break;
    //            next = str[os];
    //            if (next == 8205 || next == 8204 || next == 65038 || next == 65039)//表情连接符+变体选择符
    //            {
    //                os++;
    //            }
    //        }
    //        else break;
    //    }
    //    if (pc > 1)
    //    {
    //        long fullCode = codeInfos[0].fullCode;
    //        for (int i = 1; i < pc; i++)
    //        {
    //            fullCode <<= codeInfos[i].hbit;
    //            fullCode |= (long)codeInfos[i].halfCode;
    //        }
    //        return fullCode;
    //    }
    //    else
    //    {
    //        return codeInfos[0].fullCode;
    //    }
    //}
}
